package com.cctc.rds.scheduler.server.storage.leveldb.manager;

import com.cctc.rds.nrpc.core.util.JsonUtils;
import com.cctc.rds.scheduler.core.task.TaskLog;
import com.cctc.rds.scheduler.core.task.TaskStatus;
import com.cctc.rds.scheduler.server.storage.leveldb.LevelDB;
import org.iq80.leveldb.DB;
import org.iq80.leveldb.DBIterator;
import org.iq80.leveldb.Snapshot;

import java.io.Closeable;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * LevelDB 内存数据库 - 历史任务日志 GC 清除（守护）管理线程。
 * 描述信息：后台自动 GC 清除一个月前执行成功的任务日志，避免内存溢出。
 */
public class ClearHistoryTaskWorker extends Thread implements Closeable {
    public ClearHistoryTaskWorker() {
        super("clear-history-task-worker");
        setDaemon(true);
    }

    @Override
    public void run() {
        while (!Thread.interrupted()) {
            DB database = LevelDB.get();
            if (database == null) return;
            long curTime = System.currentTimeMillis();
            try (Snapshot snapshot = database.getSnapshot(); DBIterator iterator = database.iterator()) {
                while (iterator.hasNext()) {
                    Map.Entry<byte[], byte[]> entry = iterator.next();
                    String value = new String(entry.getValue(), StandardCharsets.UTF_8);
                    TaskLog taskLog = JsonUtils.fromJson(value, TaskLog.class);
                    long scheduleTime = taskLog.getRetryScheduleTime() > 0 ?
                            taskLog.getRetryScheduleTime() : taskLog.getScheduleTime();
                    if (curTime - scheduleTime < 24 * 60 * 60 * 31) continue;
                    TaskStatus status = TaskStatus.getInstance(taskLog.getStatus());
                    switch (status) {
                        case PENDING:
                        case CANCEL:
                        case SCHEDULING:
                        case SUCCESS:
                            database.delete(entry.getKey());
                            break;
                        case FAIL:
                        default:
                    }
                }
                try {
                    TimeUnit.MILLISECONDS.sleep(100);
                } catch (InterruptedException e) {
                }
            } catch (IOException e) {
                return;
            }
            try {
                TimeUnit.DAYS.sleep(1);
            } catch (InterruptedException e) {
            }
        }
    }

    @Override
    public void close() throws IOException {
        this.interrupt();
    }
}
